﻿using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Threading;
using FarseerGames.FarseerPhysics.Mathematics;
using FreeGoo.GameEngine;
using FreeGoo.GameEngine.Renderables.Particles;
using FreeGoo.LevelClasses;
using FreeGoo.WpfRenderer;
using FreeGoo.WpfRenderer.MouseCursor;

namespace FreeGoo.WpfDemo
{
    /// <summary>
    /// Interaction logic for GameControl.xaml
    /// </summary>
    public partial class GameControl : UserControl
    {
        private readonly Stopwatch _scrollStopwatch = new Stopwatch();

        private DispatcherTimer _dispatcherTimer;
        private Stopwatch _renderTimer = new Stopwatch();
        private WpfMouseCursor _mouseCursor;
        private Canvas _renderTarget;
        private Level _level;
        private CampaignHandler _handler;

        public GameControl()
        {
            InitializeComponent();
#if !SILVERLIGHT
            RenderTarget.RenderTransformOrigin = new Point(0.5, 0.5);
#endif
        }

        public GameControl(CampaignHandler handler, Level level)
            : this()
        {
            Level = level;
            _handler = handler;
        }

        public Engine Engine { get; private set; }
        public Level Level
        {
            get
            {
                return _level;
            }
            set
            {
                _level = value;
                Engine.CurrentLevel = _level;
            }
        }

        // Todo: this should be executed automatically
        public void UpdateRenderTargetSize()
        {
            LeftBar.Height = RenderTarget.Height;
            RightBar.Height = RenderTarget.Height;
            TopBar.Width = RenderTarget.Width;
            BottomBar.Width = RenderTarget.Width;
            RightBar.SetValue(Canvas.LeftProperty, RenderTarget.Width - 5.0);
            BottomBar.SetValue(Canvas.TopProperty, RenderTarget.Height - 5.0);
            UpdateZoomLevel();
        }

        public void UpdateZoomLevel()
        {
            // Figure out zoom levels
            if (Engine != null && Engine.CurrentLevel != null)
            {
                double zoomLevelWidth = ScrollViewer.ActualWidth / Engine.CurrentLevel.ShowSize.X;
                double zoomLevelHeight = ScrollViewer.ActualHeight / Engine.CurrentLevel.ShowSize.Y;
                double zoomLevel = zoomLevelWidth < zoomLevelHeight ? zoomLevelWidth : zoomLevelHeight;
                CanvasScaleTransform.ScaleX = zoomLevel;
                CanvasScaleTransform.ScaleY = zoomLevel;
            }
        }

        public void SetHandlerAndLevel(CampaignHandler handler, Level level)
        {
            _handler = handler;
            _level = level;
        }

        private void OnLevelLoaded(object sender, EventArgs args)
        {
            UpdateRenderTargetSize();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            SetupScrolling();

            _renderTarget = RenderTarget;

            _mouseCursor = new WpfMouseCursor(_renderTarget, 15, 5, 15);

            Engine = new Engine(new Vector2((float)1280, (float)1024), new RendererFactory(_renderTarget));
            Engine.LevelLoaded += OnLevelLoaded;

            if (_handler != null)
            {
                _handler.Engine = Engine;
            }

            _renderTimer.Start();

            _dispatcherTimer = new DispatcherTimer();
            _dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 10);
            _dispatcherTimer.Tick += _dispatcherTimerTick;
            _dispatcherTimer.Start();

            Engine.CurrentLevel = _level;
        }

        private void _dispatcherTimerTick(object sender, EventArgs e)
        {
            _mouseCursor.UpdateCursorPosition();

            if (!Engine.UserInputController.IsMouseDown && CrossMouse.IsLeftButtonDown)
            {
                Engine.UserInputController.MouseDown(new Vector2((float)_mouseCursor.Position.X, (float)_mouseCursor.Position.Y));
            }
            else if (Engine.UserInputController.IsMouseDown && CrossMouse.IsLeftButtonDown == false)
            {
                Engine.UserInputController.MouseUp();
            }

            Engine.ProgressUtil((float)_renderTimer.Elapsed.TotalSeconds);
            UpdateScroll();
        }

        private void Canvas_MouseMove(object sender, MouseEventArgs e)
        {
            _mouseCursor.UpdateCursorPosition();
            Engine.UserInputController.MouseMove(Utilities.PointToVector2(e.GetPosition(_renderTarget)));
            _mousePoint = e.GetPosition(ScrollViewer);
#if !SILVERLIGHT
            if (e.RightButton == MouseButtonState.Pressed)
            {
                Vector delta = Point.Subtract(_mouseDownPos, _mousePoint);
                ScrollViewer.ScrollToHorizontalOffset(_scrollStartPos.X + delta.X);
                ScrollViewer.ScrollToVerticalOffset(_scrollStartPos.Y + delta.Y);
            }
#endif
        }

        private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
        {
#if SILVERLIGHT
            CrossMouse.MouseLeftButtonDown(e.GetPosition);           
#endif

            if (CrossMouse.IsLeftButtonDown)
            {
                Engine.UserInputController.MouseDown(Utilities.PointToVector2(e.GetPosition(_renderTarget)));
            }
            _mouseDownPos = e.GetPosition(ScrollViewer);
            _scrollStartPos = new Point(
                ScrollViewer.HorizontalOffset,
                ScrollViewer.VerticalOffset);
        }

        private void Canvas_MouseUp(object sender, MouseButtonEventArgs e)
        {
            Engine.UserInputController.MouseUp(Utilities.PointToVector2(e.GetPosition(_renderTarget)));
        }

        private void ScrollViewer_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            UpdateZoomLevel();
        }

        private void UserControl_Unloaded(object sender, RoutedEventArgs e)
        {
            _dispatcherTimer.Stop();
        }
    }
}
